/****************************************************
	文件：HelperUtil.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2020/9/19 20:5:5
	功能：运行时的帮助方法
*****************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Serialization;
using UnityEngine;

namespace HTUtility
{
    public class HelperUtil
    {


        #region 反射相关
        /// <summary>
        ///  通过反射获取对象内部变量/属性值
        /// </summary>
        /// <param name="obj">待反射对象</param>
        /// <param name="memberName">变量名</param>
        /// <param name="bindingFlags">反射参数</param>
        /// <returns></returns>
        public static object GetMemberValue(object obj, string memberName, BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)
        {
            object value = null;
            Type type = obj.GetType();
            MemberInfo[] memberInfos = type.GetMember(memberName, bindingFlags);
            foreach (MemberInfo memberInfo in memberInfos)
            {
                switch (memberInfo.MemberType)
                {
                    case MemberTypes.Field:
                        value = type.GetField(memberName, bindingFlags).GetValue(obj);
                        break;
                    case MemberTypes.Property:
                        value = type.GetProperty(memberName, bindingFlags).GetValue(obj);
                        break;
                }
            }
            return value;
        }
        /// <summary>
        /// 通过反射设置对象内部变量/属性值
        /// </summary>
        /// <param name="obj">待反射对象</param>
        /// <param name="memberName">变量名</param>
        /// <param name="value">待设置的值</param>
        /// <param name="bindingFlags">反射参数</param>
        public static void SetMemberValue(object obj, string memberName, object value, BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)
        {
            Type type = obj.GetType();
            MemberInfo[] memberInfos = type.GetMember(memberName, bindingFlags);
            foreach (MemberInfo memberInfo in memberInfos)
            {
                switch (memberInfo.MemberType)
                {
                    case MemberTypes.Field:
                        FieldInfo fieldInfo = type.GetField(memberName);
                        fieldInfo.SetValue(obj, value);
                        break;
                    case MemberTypes.Property:
                        PropertyInfo propertyInfo = type.GetProperty(memberName);
                        propertyInfo.SetValue(obj, value);
                        break;
                }
            }
        }
        /// <summary>
        /// 通过反射设置对象内部变量/属性值
        /// </summary>
        /// <param name="obj">待反射对象</param>
        /// <param name="memberName">变量名</param>
        /// <param name="valueStr">字符串形式的值</param>
        /// <param name="bindingFlags">反射参数</param>
        public static void SetMemberValue(object obj, string memberName, string valueStr, BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)
        {
            object value = null;
            Type type = obj.GetType();
            MemberInfo[] memberInfos = type.GetMember(memberName, bindingFlags);
            foreach (MemberInfo memberInfo in memberInfos)
            {
                switch (memberInfo.MemberType)
                {
                    case MemberTypes.Field:
                        FieldInfo fieldInfo = type.GetField(memberName);
                        value = TypeDescriptor.GetConverter(fieldInfo.FieldType).ConvertFromInvariantString(valueStr);
                        fieldInfo.SetValue(obj, value);
                        break;
                    case MemberTypes.Property:
                        PropertyInfo propertyInfo = type.GetProperty(memberName);
                        value = TypeDescriptor.GetConverter(propertyInfo.PropertyType).ConvertFromInvariantString(valueStr);
                        propertyInfo.SetValue(obj, value);
                        break;
                }
            }
        }
        /// <summary>
        /// 反射调用方法
        /// </summary>
        /// <param name="obj">待反射对象</param>
        /// <param name="method">方法名</param>
        /// <param name="bindingFlags">反射参数</param>
        /// <param name="paramArray">方法参数列表</param>
        /// <returns></returns>
        public static object InvokeMethod(object obj, string method, BindingFlags bindingFlags = BindingFlags.Default | BindingFlags.InvokeMethod, params object[] paramArray)
        {
            return obj.GetType().InvokeMember(method, bindingFlags, null, obj, paramArray);
        }
        /// <summary>
        /// 反射创建类实例
        /// </summary>
        /// <param name="fullClassName">类名（包含命名空间）</param>
        /// <returns></returns>
        public static object CreateClassObj(string fullClassName)
        {
            object obj = null;
            Type type = null;
            foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = asm.GetType(fullClassName);
                if (type != null)
                {
                    obj = Activator.CreateInstance(type);
                    break;
                }
            }
            return obj;
        }
        /// <summary>
        /// 反射创建类实例（调用无参构造函数）
        /// </summary>
        /// <typeparam name="T">类的类型</typeparam>
        /// <returns></returns>
        public static T CreateClassObj<T>() where T : class, new()
        {
            Type t = typeof(T);
            ConstructorInfo constructor = t.GetConstructor(Type.EmptyTypes);
            return (T)constructor.Invoke(null); //调用无参的构造函数
        }
        /// <summary>
        /// 反射创建List
        /// </summary>
        /// <param name="itemType">List内元素的类型</param>
        /// <returns></returns>
        public static object CreateList(Type itemType)
        {
            Type lstType = typeof(List<>);
            Type specType = lstType.MakeGenericType(new Type[] { itemType }); //确定 泛型 类型
            object lst = Activator.CreateInstance(specType, new object[] { }); //new 出 List
            return lst;
        }
        #endregion

        #region 序列化与反序列化相关
        /// <summary>
        /// 对象 转 Xml
        /// </summary>
        /// <param name="path">Xml存储地址</param>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        public static bool ObjToXml(string path, System.Object obj)
        {
            try
            {
                using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                    {
                        //XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
                        //namespaces.Add(string.Empty, string.Empty);
                        XmlSerializer xs = new XmlSerializer(obj.GetType());
                        xs.Serialize(sw, obj);
                    }
                }
                return true;
            }
            catch (Exception e)
            {
                HTLogger.Error("ObjToXml error，Type is {0}；Error：{1}", obj.GetType(), e.ToString());
                return false;
            }
        }
        /// <summary>
        /// Xml 转 对象（编辑器模式）
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="path">Xml地址</param>
        /// <returns></returns>
        public static T XmlToObjInEditor<T>(string path) where T : class
        {
            T t = default(T);
            try
            {
                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    XmlSerializer xs = new XmlSerializer(typeof(T));
                    t = (T)xs.Deserialize(fs);
                }
            }
            catch (Exception e)
            {
                HTLogger.Error("XmlToObjInEditor error，Type is {0}；Error：{1}", typeof(T), e.ToString());
            }
            return t;
        }
        /// <summary>
        /// Xml 转 对象（编辑器模式）
        /// </summary>
        /// <param name="path">Xml地址</param>
        /// <param name="t">对象类型</param>
        /// <returns></returns>
        public static System.Object XmlToObjInEditor(string path, Type t)
        {
            System.Object obj = null;
            try
            {
                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    XmlSerializer xs = new XmlSerializer(t);
                    obj = xs.Deserialize(fs);
                }
            }
            catch (Exception e)
            {
                HTLogger.Error("XmlToObjInEditor error，Type is {0}；Error：{1}", t.GetType().ToString(), e.ToString());
            }
            return obj;
        }
        /// <summary>
        /// 对象 转 二进制
        /// </summary>
        /// <param name="path">二进制存储地址</param>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        public static bool ObjToBinary(string path, System.Object obj)
        {
            try
            {
                using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    bf.Serialize(fs, obj);
                }
                return true;
            }
            catch (Exception e)
            {
                HTLogger.Error("ObjToBinary error，Type is {0}；Error：{1}", obj.GetType(), e.ToString());
                return false;
            }
        }
        /// <summary>
        /// 二进制 转 对象（编辑器模式）
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="path">二进制地址</param>
        /// <returns></returns>
        public static T BinaryToObjInEditor<T>(string path) where T : class
        {
            T t = default(T);
            try
            {
                using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    t = (T)bf.Deserialize(fs);
                }
            }
            catch (Exception e)
            {
                HTLogger.Error("BinaryToObjInEditor error，Type is {0}；Error：{1}", typeof(T), e.ToString());
            }
            return t;
        }
        #endregion

        #region File 相关
        /// <summary>
        /// 检查指定文件夹是否存在，不存在则创建
        /// </summary>
        /// <param name="folderPath"></param>
        public static void CheckOrCreateFolder(string folderPath)
        {
            if (Directory.Exists(folderPath) == false)
            {
                Directory.CreateDirectory(folderPath);
            }
        }
        /// <summary>
        /// 将字符串写入指定路径的文件中
        /// </summary>
        /// <param name="content">待写入内容</param>
        /// <param name="filePath">文件路径</param>
        /// <param name="encoding">编码格式</param>
        public static void WriteStringToFile(string content, string filePath, Encoding encoding)
        {
            using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
            {
                using (TextWriter txtWriter = new StreamWriter(fs, encoding))
                {
                    txtWriter.Write(content);
                }
            }
        }
        /// <summary>
        /// 获取文件名（不含后缀）
        /// 文件路径：xxx/xxxx/xx.xxx
        /// </summary>
        /// <param name="path">文件路径</param>
        /// <param name="suffix">后缀（.xxx）</param>
        /// <returns></returns>
        public static string GetFileName(string path, string suffix)
        {
            if (string.IsNullOrEmpty(path)) return null;
            string[] table = path.Split('/');
            return table[table.Length - 1].Replace(suffix, string.Empty);
        }
        /// <summary>
        /// 搜索指定文件夹下所有的文件（DFS）
        /// </summary>
        public static List<string> GetFilesInFolder(string folderPath)
        {
            List<string> ret = new List<string>();
            FindFilesByDfs(folderPath, ref ret);
            return ret;
        }
        /// <summary>
        /// 通过文件后缀名来过滤文件路径集合
        /// </summary>
        public static List<string> FilterFileListBySuffix(IEnumerable<string> fileList, string suffix)
        {
            List<string> ret = new List<string>();
            foreach (var item in fileList)
            {
                if (item.EndsWith(suffix))
                {
                    ret.Add(item);
                }
            }
            return ret;
        }
        #endregion

        #region 正则相关
        /// <summary>
        /// 验证字符串为数字（使用正则表达式）
        /// </summary>
        public static bool IsNumeric(string value)
        {
            return Regex.IsMatch(value, @"^[-+]?\d+(\.\d+)?$");
        }
        /// <summary>
        /// 判断是否为文件夹
        /// </summary>
        /// <param name="path">路径</param>
        /// <returns></returns>
        public static bool IsFolder(string path)
        {
            return !Regex.IsMatch(path, @"\.[\w]+$");
        }
        #endregion

        #region 字符串相关

        #endregion

        #region Private Function
        /// <summary>
        /// 使用 DFS 搜索指定文件夹下所有子文件
        /// </summary>
        /// <param name="rootPath">文件夹路径</param>
        /// <param name="pathList">返回的子文件路径集合</param>
        private static void FindFilesByDfs(string rootPath, ref List<string> pathList)
        {
            DirectoryInfo info = new DirectoryInfo(rootPath);
            foreach (var subFiles in info.GetFiles())
            {
                string suffix = Path.GetExtension(subFiles.FullName);
                pathList.Add(subFiles.FullName);
            }
            foreach (var subDire in info.GetDirectories())
            {
                string subPath = subDire.FullName;
                FindFilesByDfs(subPath, ref pathList);
            }
        }
        #endregion
    }
}
